<?php

namespace asyncService\lib;

class multiProcess
{

    /**
     * @var superGlobalVariable
     */
	static $_data;

	static $_data_key = ['m_pid',"child_works_pids","parent_work_pid","new_index"];

	/**********************************************/

	//public $child_works_pids;

    public $parent_callback;

    public $child_callback ;

    public $max_precess=0;

	protected $stop = false;

	protected $_messageKey ;

    public function __construct($max_precess,$_messageKey = 0){
        $this->max_precess  = $max_precess;
        $this->_messageKey = $_messageKey;
	    self::$_data = new superGlobalVariable(10240);
    }

    public function bindSubCallback(\Closure $callback){
        $this->child_callback = $callback;
    }

    public function bindParentCallback(\Closure $callback){
        $this->parent_callback = $callback;
    }

    public function stopProcess(){

		$this->stop = true;

	    \swoole_process::kill($this->parent_work_pid);

	    foreach ($this->child_works_pids as $pid){
		    \swoole_process::kill($pid);
	    }

    }

    public function run(){


        $this->m_pid = posix_getpid();

        $this->createProcess();

        $this->processWait();
    }


    public function createProcess(){

        $this->CreateSingleProcess(null,true);

        for ($i=0; $i < $this->max_precess; $i++) {
            $this->CreateSingleProcess();
        }


    }

    public function CreateSingleProcess($index=null,$isParent = false){
		$the = $this;

        $process = new \swoole_process(function(\swoole_process $worker)use($index,$isParent,$the){
            if(is_null($index)){
                $index=$the->new_index;
	            $the->new_index++;

            }
            if($isParent){
                call_user_func_array($this->parent_callback,array($worker));
            }else{
                call_user_func_array($this->child_callback,array($worker));
            }

        }, false, false);

        $process->freeQueue();

        $process->useQueue($this->_messageKey);

        /*if($isParent){
            $process->useQueue($this->_messageKey, 2 | \swoole_process::IPC_NOWAIT);
        }else{
            $process->useQueue($this->_messageKey);
        }*/

        $pid=$process->start();

        if($isParent){
            $this->parent_work_pid = $pid;
        }else{
	        //$this->child_works_pids[] = $pid;
        	self::$_data->pushArray("child_works_pids",$pid);
        }

        return $pid;
    }

    /**
     * 重置
     * @param $worker
     */
    public function checkMpid(&$worker){
        if(!\swoole_process::kill($this->m_pid,0)){
            $worker->exit();
        }
    }

    public function rebootProcess($ret){
        $pid=$ret['pid'];

        if($pid == $this->parent_work_pid){
            $this->CreateSingleProcess(null,true);
        }else{

            $index=array_search($pid, $this->child_works_pids);
            if($index!==false){
                $index=intval($index);
                $new_pid=$this->CreateSingleProcess($index);

                return;
            }
            throw new \Exception('rebootProcess Error: no pid');
        }

    }

    public function processWait(){


        $isRun = true;
        while($isRun) {
            if(count($this->child_works_pids)){
                $ret = \swoole_process::wait();
                if ($ret && ($ret['code'] !== 0) ) {
                    $this->rebootProcess($ret);
                }
                if($ret == false && ($ret['code'] !== 0) ){
                	$isRun = false;
                }
            }else{
                break;
            }
        }
    }

    function __set( $name, $value ) {
    	if(in_array($name,self::$_data_key)){
    		self::$_data->set($name,$value);
		    return ;
	    }
	    return null;
    }

    function __get( $name ) {
	    if(in_array($name,self::$_data_key)){
		    return self::$_data->get($name);
	    }
	    return null;
    }
}